#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QResizeEvent>
#include <QtGui/QApplication>
#include <QtGui/QMenu>
#include <QtCore/QEvent>
#include <QtCore/QThread>
#include <QtDesigner/QDesignerWidgetFactoryInterface>
#include <abstractwidgetbox.h>

#include "private/pluginmanager_p.h"
#include "private/qdesigner_integration_p.h"
#include "formeditorw.h"

#include "widgetboxw.h"

class WidgetBoxUpdateEvent: public QEvent
{
public:
    WidgetBoxUpdateEvent(const QString &path) : QEvent(QEvent::Type(QEvent::User + 1))
    {
        m_path = path;
    }

    QString path()
    {
        return m_path;
    }

private:
    QString m_path;
};

WidgetBoxW *WidgetBoxW::m_self = 0;

WidgetBoxW::WidgetBoxW(QWidget *parent) : QWidget(parent), m_initialized(false)
{
    if (m_self != 0)
        delete m_self;

    m_self = this;
    FormEditorW::instance()->setWidgetBox(this);
}

WidgetBoxW::~WidgetBoxW()
{
    m_self = 0;
    FormEditorW::instance()->setWidgetBox(0);

    if (m_initialized)
    {
        QDesignerWidgetBoxInterface *editor = FormEditorW::instance()->formEditor()->widgetBox();
        editor->hide();
        editor->setParent(0);
    }

    FormEditorW::instance()->updateTopLevel();
}


void WidgetBoxW::initialize()
{
    if (!m_initialized)
    {
        m_initialized = true;
        FormEditorW::instance()->initialize();

        QDesignerWidgetBoxInterface *editor = 0;

        if (!FormEditorW::instance()->formEditor()->widgetBox())
        {
            editor = QDesignerComponents::createWidgetBox(FormEditorW::instance()->formEditor(), this);
            FormEditorW::instance()->formEditor()->setWidgetBox(editor);
        }
        else
        {
            editor = FormEditorW::instance()->formEditor()->widgetBox();
            editor->setParent(this);
        }

        Q_ASSERT(editor);

        editor->resize(size());
        editor->move(pos());
        editor->show();

        if (!FormEditorW::instance()->updateTopLevel())
            FormEditorW::instance()->formEditor()->setTopLevel(editor);
    }
}

void WidgetBoxW::updateCustomWidgets()
{
    if (qApp->thread() == QThread::currentThread())
        QApplication::sendEvent(this, new QEvent(QEvent::Type(QEvent::User + 2)));
    else
        QApplication::postEvent(this, new QEvent(QEvent::Type(QEvent::User + 2)));
}

WidgetBoxW *WidgetBoxW::instance()
{
    if (m_self == 0)
        m_self = new WidgetBoxW();

    m_self->initialize();

    return m_self;
}

void WidgetBoxW::updateCustomWidgetLocation(const QString &path)
{
    if (qApp->thread() == QThread::currentThread())
        QApplication::sendEvent(this, new WidgetBoxUpdateEvent(path));
    else
        QApplication::postEvent(this, new WidgetBoxUpdateEvent(path));

    updateCustomWidgets();
}

bool WidgetBoxW::event(QEvent *e)
{
    if (e->type() == QEvent::User + 1)
    {
        QString path = ((WidgetBoxUpdateEvent *)e)->path();
        QDesignerPluginManager *pluginManager = FormEditorW::instance()->formEditor()->pluginManager();
        QStringList registeredPlugins = pluginManager->registeredPlugins();

        Q_FOREACH (QString registeredPlugin, registeredPlugins)
        {
            QObject *plugin = pluginManager->instance(registeredPlugin);

            if (QByteArray(plugin->metaObject()->className()) == QByteArray("JambiCustomWidgetCollection"))
            {
                QMetaObject::invokeMethod(plugin, "loadPlugins", Q_ARG(QString, path), Q_ARG(QObject *, FormEditorW::instance()->formEditor()->widgetFactory()));
            }
        }

        return true;
    }
    else if (e->type() == QEvent::User + 2)
    {
        if (qdesigner_internal::QDesignerIntegration *integration = qobject_cast<qdesigner_internal::QDesignerIntegration *>(FormEditorW::instance()->formEditor()->integration()))
        {
            integration->updateCustomWidgetPlugins();
        }

        return true;
    }
    else
    {
        return QWidget::event(e);
    }
}

bool WidgetBoxW::initializeJambiPlugins(const QString &jambiBase, const QString &jambiPluginPath, const QString &customWidgetClassPath, const QString &resourcePath, const QString &jvm)
{
    return FormEditorW::instance()->initializeJambiPlugins(jambiBase, jambiPluginPath, customWidgetClassPath, resourcePath, jvm);
}

void WidgetBoxW::resizeEvent(QResizeEvent *event)
{
    QDesignerWidgetBoxInterface *editor = FormEditorW::instance()->formEditor() != 0 ? FormEditorW::instance()->formEditor()->widgetBox() : 0;

    if (editor != 0)
        editor->resize(event->size());

    QWidget::resizeEvent(event);
}

QSize WidgetBoxW::minimumSize()
{
    QDesignerWidgetBoxInterface *editor = FormEditorW::instance()->formEditor() != 0 ? FormEditorW::instance()->formEditor()->widgetBox() : 0;

    if (editor != 0)
        return editor->minimumSize();
    else
        return QWidget::minimumSize();
}

void WidgetBoxW::setBoxEnabled(bool state)
{
    setEnabled(state);
}

QString WidgetBoxW::pluginFailureString() const
{
    return FormEditorW::instance()->pluginFailureString();
}
